<form novalidate [formGroup]="user" (ngSubmit)="onSubmit()">
  <div class="form-group">
    <label class="form-label">username:</label>
    <input type="text" class="form-control" placeholder="请输入username" formControlName="username">
    <!-- 多项验证使用get().invalid, 获取验证结果, 具体某一项使用; get().hasError('required') -->
    <div class="error" *ngIf="user.get('username').invalid && user.get('username').touched">请输入5-8位用户名</div>
  </div>
  <div class="form-group">
    <label class="form-label">email:</label>
    <input type="text" class="form-control" placeholder="请输入email" formControlName="email">
    <div class="error" *ngIf="user.get('email').invalid && user.get('email').touched">请输入合法的邮箱地址****@.qq.com</div>
  </div>
  <div class="form-group">
    <label class="form-label">password:</label>
    <!-- 1.若未设置 reverse 属性或属性值为 false，实现的功能跟前面的一样。
         2.若 reverse 的值设置为 true，我们仍然会执行相同的验证，但错误信息不是添加到当前控件，而是添加到目标控件上。 -->
    <input type="text" class="form-control" placeholder="请输入password" formControlName="password" validateEqual="confirmPassword" reverse="true">
    <div class="error" *ngIf="user.get('password').invalid && user.get('password').touched">请输入密码</div>
  </div>
  <div class="form-group">
    <label class="form-label">confirmPassword:</label>
    <input type="text" class="form-control" placeholder="请确认密码" formControlName="confirmPassword" validateEqual="password">
    <div class="error" *ngIf="user.get('confirmPassword').invalid && user.get('confirmPassword').touched">两次密码不一致</div>
  </div>
  <!-- tips: fromGroup, fromControl公共类的属性值： value, valid, invalid， touched -->
  <button class="btn btn-primary" [disabled]="user.invalid" type="primary">提交</button>
</form>

<div class="">
  formGroup的属性:
  <div>value: {{user.value | json}}</div>
  <div>valid: {{user.valid}}</div>
  <div>invalid: {{user.invalid}}</div>
  <div>touched: {{user.touched}}</div>
</div>
